NoSuchMethodException when forcing the use of Log4J2LoggingSystem using org.springframework.boot.logging.LoggingSystem system property#49343
Conversation
Signed-off-by: Fabrice Bibonne <fabrice.bibonne@courriel.eco>
- fix the missing constructor in Log4J2LoggingSystem class (can be called by LoggingSystem.get(ClassLoader, String) Signed-off-by: Fabrice Bibonne <fabrice.bibonne@courriel.eco>
Signed-off-by: Fabrice Bibonne <fabrice.bibonne@courriel.eco>
|
Thanks for the PR.
Can you please share some details about the error that occurs with 3.5.x? I can't reproduce a failure with that version. Furthermore, there's a |
|
With Spring Boot 3.5.11 (in the project located at https://framagit.org/FBibonne/poc-java/-/tree/spring-boot-force-log4j2, I set the version of spring-boot-starter-parent at 3.5.11), I get this error if I run the poc.Main class : It is true that the constructor of Log4J2LoggingSystem exists and is called successfully. But the exception above is raised just after (nex line in org.springframework.boot.context.logging.LoggingApplicationListener#onApplicationStartingEvent). I think that this class cast exception is what PR #47424 pointed out. So if I exclude spring-boot-starter-logging from the dependencies, the exception above does not occur and the application does not crash. Sorry, I missed the exclusion. |
org.springframework.boot.logging.LoggingSystem property
core/spring-boot/src/test/java/org/springframework/boot/logging/LoggingSystemTests.java
Show resolved
Hide resolved
core/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/Log4J2LoggingSystem.java
Show resolved
Hide resolved
core/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/Log4J2LoggingSystem.java
Outdated
Show resolved
Hide resolved
- refactor the test for log4j - add test for JUL Signed-off-by: Fabrice Bibonne <fabrice.bibonne@courriel.eco>
- code sharing between factory and constructor - unique origin for the loggerContext generated inside the class Signed-off-by: Fabrice Bibonne <fabrice.bibonne@courriel.eco>
…ge private Signed-off-by: Fabrice Bibonne <fabrice.bibonne@courriel.eco>
core/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/Log4J2LoggingSystem.java
Outdated
Show resolved
Hide resolved
core/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/Log4J2LoggingSystem.java
Outdated
Show resolved
Hide resolved
…LoggerContext) - see comment spring-projects#49343 (comment) Signed-off-by: Fabrice Bibonne <fabrice.bibonne@courriel.eco>
…lassLoader, LoggerContext) removal - remove LoggerContext from LoggerContextFactory after each unit test to avoid that it is reused Signed-off-by: Fabrice Bibonne <fabrice.bibonne@courriel.eco>
| this.loggingSystem.getConfiguration().stop(); | ||
| this.loggingSystem.cleanUp(); | ||
| PluginRegistry.getInstance().clear(); | ||
| LogManager.getFactory().removeContext(this.loggingSystem.getLoggerContext()); |
| assertThat(configuration.getConfigurationSource().getFile()).isNotNull(); | ||
| assertThat(configuration.getConfigurationSource().getLocation()).contains("log4j2-test.xml"); |
There was a problem hiding this comment.
This change appears to be unrelated. Please revert
| * Create a new {@link Log4J2LoggingSystem} instance. | ||
| * Create a new {@link Log4J2LoggingSystem} instance. The loggerContext is | ||
| * instantiated internally in the class from | ||
| * {@link LogManager#getContext(ClassLoader, boolean)} <br/> | ||
| * This constructor is also intended to be used by | ||
| * <code>LoggingSystem.get(ClassLoader, String)</code> with reflection. | ||
| * @param classLoader the class loader to use. | ||
| * @param loggerContext the {@link LoggerContext} to use. | ||
| * @throws IllegalArgumentException if the loggerContext instantiated internally is | ||
| * not of type org.apache.logging.log4j.core.LoggerContext |
There was a problem hiding this comment.
I don't think these changes add much, particular not the part that's describing what the code does. We generally reserve comments for situations where we need to describe why something is the way it is. The code itself describes the what. Please revert. This will leave this constructor more closely aligned with the other logging system constructors.
There was a problem hiding this comment.
Ok. I just wonder if you have an other way that the test to figure that the constructor is called using the reflection API (seems to be important to avoid accidental removing)
The Spring Boot documentation states that users can force a particular logging system by setting the system property
org.springframework.boot.logging.LoggingSystemto the fully qualified class name of aLoggingSystemimplementation.When attempting to do so for Log4J2 (setting
org.springframework.boot.logging.LoggingSystem = org.springframework.boot.logging.log4j2.Log4J2LoggingSystem), Spring Boot crashes with the following error (Spring Boot 4.0.3):A different error occurs with Spring Boot 3.5.x, but this PR focuses on Spring Boot 4.
Reproduction
The issue can be reproduced by running the following
mainmethod withspring-boot-starterandspring-boot-starter-log4j2on the classpath (with java 25):An example project is available at: https://framagit.org/FBibonne/poc-java/-/tree/spring-boot-force-log4j2 (make sure to stay on the
spring-boot-force-log4j2branch).Root cause and fix
The error message above (
java.lang.NoSuchMethodException: org.springframework.boot.logging.log4j2.Log4J2LoggingSystem.<init>) indicates that a specific constructor is missing in Log4J2LoggingSystem : the missing constructor was removed in PR #47424. This PR proposes reintroducing it as aprivateconstructor (to prevent unintentional direct use) since it is invoked via reflection. The constructor body reuses the code introduced by PR #47424 inorg.springframework.boot.logging.log4j2.Log4J2LoggingSystem.Factoryto obtain aloggerContext.The test
org.springframework.boot.logging.LoggingSystemTests#log4J2CanBeForcedreproduces the problem: it fails ifLog4J2LoggingSystemis not fixed.Note on tests
The build of the
core/spring-bootmodule succeeds; however, the full project build fails due to some container-based tests:DataLdapTestDockerTests,OpenLdapContainerConnectionDetailsFactoryIntegrationTests,OpenLdapDockerComposeConnectionDetailsFactoryIntegrationTests: disabled because they require exposing a privileged port (389), which is not permitted on my machine.PulsarDockerComposeConnectionDetailsFactoryIntegrationTests: required adding the propertyservices.pulsar.security_optwith the valueseccomp:unconfinedinpulsar-compose.yamlto bypass a security restriction.ZipkinContainerConnectionDetailsFactoryIntegrationTests: disabled — root cause not yet identified.